package server

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"adai.design/homemaster/container"
	"adai.design/homemaster/log"
	"reflect"
	"adai.design/homemaster/modules"
	"encoding/base64"
)

type Message struct {
	Path 	string		`json:"path"`
	Method  string		`json:"method"`
	State 	string		`json:"state,omitempty"`
	Data 	json.RawMessage		`json:"data,omitempty"`
}

type Characteristic struct {
	AccessoryID 	string		`json:"aid"`
	ServiceId 		int			`json:"sid"`
	CharacteristicId  int 		`json:"cid"`
	Value 	 	interface{}		`json:"value"`
}


const (
	MsgPathAccessories = "accessories"
	MsgPathCharacteristics = "characteristics"
	MsgPathContainer = "container"
	MsgPathTest = "test"
	MsgPathWifiConfig = "wificonfig"

	MsgMethodPost = "post"
	MsgMethodGet = "get"
	MsgMethodPut = "put"
)

type Handler interface {
	Handle(client *websocket.Conn, msg *Message) error
}

var messageHandleMap = map[string]Handler{}

// 属性信息梳理
type CharacteristicController struct {
}

func (c *CharacteristicController) Handle(client *websocket.Conn, msg *Message) error  {
	if msg.Method == MsgMethodGet {
		chars := make([]*Characteristic, 0)
		accessories := container.GetContainer().Accessories
		for _, a := range accessories {
			for _, s := range a.Services {
				for _, c := range s.Characteristics {
					char := &Characteristic{
						AccessoryID: a.UUID,
						ServiceId: s.ID,
						CharacteristicId: c.Id,
						Value: c.Value,
					}
					chars = append(chars, char)
				}
			}
		}

		data, _ := json.Marshal(chars)
		result := &Message{
			Path: msg.Path,
			Method: msg.Method,
			Data: data,
			State: "ok",
		}
		buffer, _ := json.Marshal(result)
		return client.WriteMessage(websocket.TextMessage, buffer)
	}

	if msg.Method == MsgMethodPost {
		var chars []*Characteristic
		err := json.Unmarshal(msg.Data, &chars)
		if err != nil {
			log.Error("err: %v", err)
			return err
		}

		accessories := container.GetContainer().Accessories
		for _, char := range chars {
			for _, a := range accessories {
				if a.UUID == char.AccessoryID {
					for _, s := range a.Services {
						if s.ID == char.ServiceId {
							for _, c := range s.Characteristics {
								if c.Id == char.CharacteristicId {
									log.Debug("aid(%s) value(%v) type(%v)", char.AccessoryID, char.Value, reflect.TypeOf(char.Value))
									c.UpdateValueFromConnection(char.Value, client)
								}
							}
						}
					}
				}
			}
		}

		return nil
	}
	return nil
}

func init() {
	messageHandleMap[MsgPathCharacteristics] = &CharacteristicController{}
}

// 配件信息处理
type AccessoryController struct {
}

func (c *AccessoryController) Handle(client *websocket.Conn, msg *Message) error {
	if msg.Method == MsgMethodGet {
		accessories := container.GetContainer().Accessories
		data, _ := json.Marshal(accessories)
		result := &Message{
			Path: msg.Path,
			Method: msg.Method,
			Data: data,
			State: "ok",
		}
		buffer, _ := json.Marshal(result)
		return client.WriteMessage(websocket.TextMessage, buffer)
	}
	return nil
}

func init() {
	messageHandleMap[MsgPathAccessories] = &AccessoryController{}
}

type TestController struct {
}

type testData struct {
	Topic 	string		`json:"topic"`
	Data 	string		`json:"data"`
}

func (c *TestController) Handle(client *websocket.Conn, msg *Message) error {
	if msg.Method == MsgMethodPost {
		var test testData
		if err := json.Unmarshal(msg.Data, &test); err != nil {
			log.Error("%s", err)
		}

		if test.Topic == "oled" {
			data, err := base64.StdEncoding.DecodeString(test.Data)
			if err == nil {
				err = modules.SetOledDisplay(data)
			}

			ret := "ok"
			if err != nil {
				ret = "failed"
			}
			result := &Message{
				Path: msg.Path,
				Method: msg.Method,
				State: ret,
			}
			buffer, _ := json.Marshal(result)
			return client.WriteMessage(websocket.TextMessage, buffer)
		}
	}
	return nil
}

func init() {
	messageHandleMap[MsgPathTest] = &TestController{}
}

type WifiController struct {
	Ssid 		string		`json:"ssid"`
	Passwd 		string		`json:"passwd"`
}

func (c *WifiController) Handle(client *websocket.Conn, msg *Message) error {
	if msg.Method == MsgMethodPost {
		err := json.Unmarshal(msg.Data, &c)
		if err == nil {
			modules.SetWifi(c.Ssid, c.Passwd)
		}
		ret := "ok"
		if err != nil {
			ret = "failed"
		}
		result := &Message{
			Path:   msg.Path,
			Method: msg.Method,
			State:  ret,
		}
		buffer, _ := json.Marshal(result)
		return client.WriteMessage(websocket.TextMessage, buffer)
	}
	return nil
}

func init() {
	messageHandleMap[MsgPathWifiConfig] = &WifiController{}
}
